/**
 * 权限守卫
 * 作者：GodMainCode
 * 创建时间：2024-01-17
 * 修改时间：2024-01-17
 * 修改人：GodMainCode
 */

import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PERMISSIONS_KEY } from '../decorators/require-permissions.decorator';
import { ROLES_KEY } from '../decorators/require-roles.decorator';
import { UserService } from '../../user/user.service';

@Injectable()
export class PermissionGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private userService: UserService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 获取路由所需的权限和角色
    const requiredPermissions = this.reflector.getAllAndOverride<string[]>(
      PERMISSIONS_KEY,
      [context.getHandler(), context.getClass()],
    );
    const requiredRoles = this.reflector.getAllAndOverride<string[]>(
      ROLES_KEY,
      [context.getHandler(), context.getClass()],
    );

    // 如果没有设置权限和角色要求，则允许访问
    if (!requiredPermissions && !requiredRoles) {
      return true;
    }

    const request = context.switchToHttp().getRequest();
    const user = request.user;

    if (!user) {
      throw new UnauthorizedException('未登录');
    }

    // 获取用户完整信息（包括角色和权限）
    const userWithRoles = await this.userService.findOne(user.id);
    
    // 检查角色
    if (requiredRoles) {
      const hasRole = userWithRoles.roles.some(role => 
        requiredRoles.includes(role.code)
      );
      if (!hasRole) {
        throw new UnauthorizedException('角色权限不足');
      }
    }

    // 检查权限
    if (requiredPermissions) {
      const userPermissions = new Set<string>();
      
      // 收集用户所有角色的权限
      for (const role of userWithRoles.roles) {
        for (const permission of role.permissions) {
          userPermissions.add(permission.code);
        }
      }

      const hasPermission = requiredPermissions.every(permission => 
        userPermissions.has(permission)
      );

      if (!hasPermission) {
        throw new UnauthorizedException('操作权限不足');
      }
    }

    return true;
  }
} 